#pragma once
#include <iostream>
#include <string>
#include <regex>
#include <sstream>
#include "Cond_type.h"
#undef max

using namespace std;

class Validator
{
public:
	Validator(void);
	~Validator(void);

	static bool valid_name(const string&);

	template <typename T>
	static T get(const string& msg = "", const string& errmsg = "Wrong input. Please try again.")
	{
		T ret;
		bool err = false;

		do
		{
			if(err)
			{
				cin.clear();
				cin.ignore(numeric_limits<streamsize>::max(), '\n');
				cout << errmsg << endl;
			}
			if(msg == "")
			{
				cout << endl << "Enter a(n) " << typeid(T).name() << ": ";
			}
			else
			{
				cout << msg;
			}
			cin >> ret;
			err = cin.fail();
		} while(err);

		return ret;
	}

	template <>
	static string get<string>(const string& msg, const string& errmsg)
	{
		string ret;
		bool err = false;

		do
		{
			if(err)
			{
				cin.clear();
				cin.ignore(numeric_limits<streamsize>::max(), '\n');
				cout << errmsg << endl;
			}
			if(msg == "")
			{
				cout << endl << "Enter a(n) string: ";
			}
			else
			{
				cout << msg;
			}
			cin >> ret;
			//cin >> noskipws >> ret;
			err = cin.fail() || !valid_name(ret);
		} while(err);

		return ret;
	}

	static Cond_type get_cond(const bool& just_eq = false)
	{
		Cond_type ret = EQ;
		string temp;
		bool err = false;

		do
		{
			if(err)
			{
				cin.clear();
				cin.ignore(numeric_limits<streamsize>::max(), '\n');
				cout << "Wrong input. Please try again." << endl;
			}
			cout << endl << "Enter a(n) relation (" << ((just_eq) ? "=" : "less/eq/more") << "): ";

			cin >> temp;
			err = cin.fail() || ((temp != "less" || just_eq) && temp != "eq" && (temp != "more") || just_eq);
		} while(err);

		if("less" == temp && !just_eq) ret = LT;
		else if("more" == temp && !just_eq) ret = GT;

		return ret;
	}


	template <typename T>
	static T* get_pointer(const bool &null_ok, const string& msg = "", const string& errmsg = "Wrong input. Please try again.")
	{
		T* ret = NULL;

		bool err = false;
		T ttemp;
		string stemp;
		stringstream ss;
		do
		{
			if(err)
			{
				cin.clear();
				cin.ignore(numeric_limits<streamsize>::max(), '\n');
				cout << errmsg << endl;
			}
			if(msg == "")
			{
				cout << endl << "Enter a(n) " << typeid(T).name() << ": ";
			}
			else
			{
				cout << msg;
			}
			cin >> stemp;

			if("null" != stemp || !null_ok)
			{
				ss << stemp;
				ss >> ttemp;

				err = cin.fail() || ss.fail();
				ss.str(string());
				ss.clear();
			}
		} while(err || ("null" == stemp && !null_ok));

		if(stemp != "null")
		{
			ret = new T(ttemp);
		}

		return ret;
	}

	template <>
	static string* get_pointer<string>(const bool &null_ok, const string& msg, const string& errmsg)
	{
		string* ret = NULL;
		bool err = false;
		string temp;

		do
		{
			if(err)
			{
				cin.clear();
				cin.ignore(numeric_limits<streamsize>::max(), '\n');
				cout << errmsg << endl;
			}
			if(msg == "")
			{
				cout << endl << "Enter a(n) string: ";
			}
			else
			{
				cout << msg;
			}
			cin >> temp;
		} while(cin.fail() || !valid_name(temp));

		if("null" != temp || !null_ok)
		{
			ret = new string(temp);
		}

		return ret;
	}


};